package middleware

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"golang.org/x/time/rate"
	"net"
	"strings"
	"time"
	"video-api/utility/redis_client"
)

// ErrorHandler 记录http接口报错信息
func ErrorHandler(r *ghttp.Request) {
	r.Middleware.Next()
	if err := r.GetError(); err != nil {
		// 记录到自定义错误日志文件
		g.Log("MiddlewareErrorHandler").Error(context.TODO(), err)
		//返回固定的友好信息
		r.Response.ClearBuffer()
		r.Response.Writeln("服务器居然开小差了，请稍后再试吧！")
	}
}

// 获取 IP 限流的 Redis 键名
func getIpKey(ip string) string {
	return fmt.Sprintf("ip_limit:%s", ip)
}

// getClientIP 获取客户端真实IP
func getClientIP(r *ghttp.Request) string {
	ip := r.Header.Get("X-Forwarded-For")
	if ip == "" {
		ip = r.GetClientIp()
	} else {
		ips := strings.Split(ip, ", ")
		if len(ips) > 0 {
			ip = ips[0]
		}
	}
	// 去除端口
	if host, _, err := net.SplitHostPort(ip); err == nil {
		ip = host
	}
	return ip
}

// RateLimitIPMiddleware 限流中间件(限制ip)
func RateLimitIPMiddleware(r *ghttp.Request) {
	ctx := r.Context()
	ip := getClientIP(r) // 获取客户端 IP
	key := getIpKey(ip)  // 为每个 IP 创建一个 Redis 键

	// 限制时间窗口
	windowDuration := time.Minute
	limit := 5 // 每分钟最大请求次数

	// 获取该 IP 的请求时间戳列表
	// 使用 Redis 的 List 类型来存储时间戳
	now := time.Now().Unix()

	// 先移除过期的请求时间戳（超过窗口时间）
	redis_client.RedisClient.LRem(ctx, key, 0, now-(int64(windowDuration.Seconds())))

	// 获取当前该 IP 的请求记录
	remainingRequests, _ := redis_client.RedisClient.LLen(ctx, key).Result()

	// 如果该 IP 的请求次数已经超过限制
	if remainingRequests >= int64(limit) {
		r.Response.WriteHeader(429)
		r.Response.WriteJson(g.Map{"message": "Too many requests from this IP. Please try again later."})
		return
	}

	// 将当前请求的时间戳添加到该 IP 的请求记录中
	redis_client.RedisClient.RPush(ctx, key, now)

	// 设置过期时间，确保过期后 Redis 会清理该 IP 的记录
	redis_client.RedisClient.Expire(ctx, key, windowDuration)

	// 继续处理请求
	r.Middleware.Next()
}

// GlobalRateLimiter 全局限流中间件
func GlobalRateLimiter() func(r *ghttp.Request) {
	limiter := rate.NewLimiter(rate.Limit(1000), 1000) // 每秒最大 1000 次请求
	//limiter := rate.NewLimiter(limit, burst)
	return func(r *ghttp.Request) {
		if !limiter.Allow() {
			r.Response.WriteHeader(429)
			r.Response.WriteJson(g.Map{"message": "Too many requests in a short period."})
			return
		}
		r.Middleware.Next()
	}
}
